<!DOCTYPE HTML>
<!--
	SARS-CoV-2 lineages
-->
<html>

{% include head.html %}

<style type="text/css">
  #map {
    width: calc(100% - 188px);
    flex-basis: calc(100% - 188px);
    height: 600px;
    margin-top: 20px;

  }

  #bar_chart {
    width: calc(100% - 188px);
    flex-basis: calc(100% - 188px);
    height: 350px;
    margin-top: 50px;

  }

  #date_chart {
    width: calc(100% - 188px);
    flex-basis: calc(100% - 188px);
    height: 300px;
    margin-top: 50px;
    margin-bottom: 90px;

  }

  #toTopBtn {
    position: fixed;
    bottom: 26px;
    right: 39px;
    z-index: 98;
    padding: 21px;
    background-color: #86b0a6
    }
  .countries {
    fill: #ccc;
    stroke: #fff;
    stroke-width: 2;
    stroke-linejoin: round;
  }

  .countryCount {
    width: 50px;
    text-align: center;
  }


  .locations{
    stroke-width: 1;
    opacity: 0.7;
  }

  .axis {
    font: 12px sans-serif;
  }
  .axis path,
  .axisBottom line {
    fill: none;
    stroke: dimgrey;
    shape-rendering: crispEdges;
    stroke-width: 1px;
  }
  .maptooltip {
    position: absolute;
    padding: 10px;
    min-width: 50px;
    min-height: 20px;
    background-color: #6E6D92;
    color: white;
    z-index: 1000000000;
    display: none;
    border-radius: 5px;
    font: 14px sans-serif;
  }


</style>


<body>
  <script>
    $(document).ready(function() {
      $(window).scroll(function() {
      if ($(this).scrollTop() > 20) {
      $('#toTopBtn').fadeIn();
      } else {
      $('#toTopBtn').fadeOut();
      }
      });
      
      $('#toTopBtn').click(function() {
      $("html, body").animate({
      scrollTop: 0
      }, 400);
      return false;
      });
      });
  </script>
  
  <script type="text/javascript">
    const updateTableFactory = (tooltipId,metadata)=>(tipId)=>{
            const data = metadata[tipId];
            const tableDiv = d3.select(document.getElementById(tooltipId));
            //Remove table
        tableDiv.html("")
            if (data !== undefined) {
                const visibleData = Object.keys(data).filter(d=>d!=='sequence_name');
                tableDiv.append("h3")
                    .attr("class",'tooltip-header')
                    .text(tipId)
                    .append("hr");
                tableDiv.selectAll("p")
                        .data(visibleData)
                        .enter()
                        .append("p")
                        .attr("class","tooltip-text")
                            .selectAll("span")
                            .data(d=>[d,data[d]])
                            .enter()
                            .append("span")
                            .attr("class",(d,i)=> i===0? "tooltip-key" :"tooltip-value")
                            .text((d,i)=>i===0? d + " : ": d);
            }
    }
    <%text>
    
    function addSliderEventHandler(sliderID,fig){
      const svg = fig.svgSelection.select(function() { return this.parentNode; })
      const initialHeight = svg.attr("height");
      const maxHeight = fig.tree().externalNodes.length*50; // 50 pixels for each tip plus a little for margins;

      if(maxHeight<=initialHeight){
        d3.select(`#${sliderID}`).remove();// don't need  a slider
        return;
      }
      const heightScale = d3.scaleLinear()
              .range([initialHeight,maxHeight])
              .domain([0,1])

          if(initialHeight/fig.tree().externalNodes.length>12){
            fig.svgSelection.selectAll(".label")
            .classed("show",true)
          }

      d3.select(`#${sliderID}`).on("input",function(){
            const svgHeight = heightScale(this.value);
            //magic number!!
            svg.attr("height", svgHeight);
          fig.update();
          if(svgHeight/fig.tree().externalNodes.filter(node=>!node[fig.id].ignore).length>12){
            fig.svgSelection.selectAll(".label")
            .classed("show",true)
          }else{
            fig.svgSelection.selectAll(".label")
            .classed("show",false)
          }
      })
    }
    </%text>

    function buildTree(svgID, myTreeString,tooltipID,backgroundDataString,sliderID) {
        const backgroundData = JSON.parse(backgroundDataString);
        const updateTable = updateTableFactory(tooltipID, backgroundData);
        const margins = {top:50,bottom:60,left:100,right:100}
        const svg = d3.select(document.getElementById(svgID))
        svg.selectAll("g").remove();
        const newickString = myTreeString;
        const tree = figtree.Tree.parseNewick(newickString);
        const fig = new figtree.FigTree(document.getElementById(svgID),margins, tree)
        fig.layout(figtree.rectangularLayout)
                .nodes(figtree.circle()
                                .filter(n=>!n.children)
                                .attr("r",8)
                                .hilightOnHover(20)
                                .onClick((node,i,n)=>{
                                  updateTable(node.name);
                                  fig.svgSelection.selectAll(".selected").classed("selected",false);
                                  d3.select(n[i]).classed("selected",true);
                                }),
                        figtree.tipLabel(v=>v.name).attr("dx",10),
                        figtree.rectangle()
                                .filter(n=>n[fig.id].collapsed)
                                .attr("width",20)
                                .attr("height",20)
                )
                      .nodeBackgrounds(figtree.circle()
                                        .attr("r", 10)
                              .filter(n=>!n.children)
                                      )
                      .branches(figtree.branch()
                                  .hilightOnHover(20) 
                                  .collapseOnClick()
                                  .on("click",()=>{
                                    const svgHeight = fig.svgSelection.select(function() { return this.parentNode; }).attr("height");
                                    if(svgHeight/fig.tree().externalNodes.filter(node=>!node[fig.id].ignore).length>12){
                                      fig.svgSelection.selectAll(".label")
                                        .classed("show",true)
                                    }else{
                                      fig.svgSelection.selectAll(".label")
                                      .classed("show",false)
                                    }
                                  })
                          )
                          .feature(
                                  figtree.scaleBar()
                                    .direction("x")
                                    .length(1/29903)
                                    .x(-60)
                                    .y(-30)
                                    // .y(fig.svgSelection.select(function() { return this.parentNode; }).attr("height")-margins.top-margins.bottom+20)
                                    .title({text:"~1 SNP",
                                    yPadding:10})
                                      )

      addSliderEventHandler(sliderID,fig);

    }
  </script>

  <script>
    $(document).ready(function() {
      $(window).scroll(function() {
      if ($(this).scrollTop() > 20) {
      $('#toTopBtn').fadeIn();
      } else {
      $('#toTopBtn').fadeOut();
      }
      });
      
      $('#toTopBtn').click(function() {
      $("html, body").animate({
      scrollTop: 0
      }, 400);
      return false;
      });
      });
  </script>

    <!-- Wrapper -->
    <div id="wrapper">

        <!-- Main -->
        <div id="main">
            <div class="inner">
              <a href="#" id="toTopBtn" class="cd-top text-replace js-cd-top cd-top--is-visible cd-top--fade-out" data-abc="true"></a>
                {% include header.html %}

                <!-- Content -->
                <section>
                	<header class="main">
                    <a href="#" id="toTopBtn" class="cd-top text-replace js-cd-top cd-top--is-visible cd-top--fade-out" data-abc="true"></a>
                		<h2>{{ page.title }}</h2>
                	</header>
                  {% if page.parent %}
                  <p>
                    <ul class="actions small">
                    <a href="/lineages/lineage_{{ page.parent }}.html" class="button special fit">Go to parent lineage: {{ page.parent }}</a>
                  </ul>
                 </p>
                 {% endif %}
                 <div id="map"></div>
                <div id="bar_chart"></div>
                <div id="date_chart"></div>
                <div id="tableWrapper">
                   <h3><strong>Table 1</strong> | Summary of lineage & sub-lineages <br>  <input class="searchbar" type="text" id="myInput" onkeyup="myFunction('myInput','myTable')" placeholder="Search for lineage..." title="searchbar"></h3>
                    <br><br>
                    <table id="myTable">
                      <tr class="header">
                        <th style="width:10%;">Lineage</th>
                        <th style="width:20%;">Most common countries</th>
                        <th style="width:15%;">Earliest date</th>
                        <th style="width:10%;">Count</th>
                        <th style="width:10%;">Travel History</th>
                        <th style="width:30%;">Description</th>
                      </tr>
                        {% for child in page.children %}

                        {% assign row = site.data.lineage_data[child] %}
                      <tr>
                        <td><a href="/lineages/lineage_{{ child }}.html" style="color:#86b0a6">{{ child }}</a> </td>
                        <td>{{ row["Countries"] }}</td>
                        <td>{{ row["Earliest date"] }}</td>
                        <td>{{ row["Count"] }}</td>
                        <td>{{ row["Travel History"] }}</td>
                        <td>{{ row["Description"] }}</td>
                      </tr>

                    {% endfor %}
                  
                  </table>
                </div>

                {{ content }}
                </section>
              </div>
          </div>
          <script>
            function myFunction(myInput, myTable) {
              var input, filter, table, tr, td, i, txtValue;
              input = document.getElementById(myInput);
              filter = input.value.toUpperCase();
              table = document.getElementById(myTable);
              tr = table.getElementsByTagName("tr");
              for (i = 0; i < tr.length; i++) {
                td = tr[i].getElementsByTagName("td")[0];
                if (td) {
                  txtValue = td.textContent || td.innerText;
                  if (txtValue.toUpperCase().indexOf(filter) > -1) {
                    tr[i].style.display = "";
                  } else {
                    tr[i].style.display = "none";
                  }
                }       
              }
            }
            </script>
          {% include sidebar.html %}

      </div>

      {% include footer.html %}

</body>

</html>

<script type="text/javascript">
  var selectedLineage = "{{page.lineage}}";
  var children = [];
  {% for child in page.children %}
  children.push("{{child}}")              
  {% endfor %}


  var continents = ["Europe", "Asia", "NorthAmerica", "SouthAmerica", "Africa", "Antarctica", "Oceania"].reverse();

  var colourMap = {
    "Europe": "#984464",
    "Asia": "#86b0a6",
    "NorthAmerica": "#52495a",
    "SouthAmerica": "#557b86",
    "Africa": "#b88f89",
    "Oceania": "#eb7e83",
    "Antarctica": "#cdcdcd"
  }

  var body = document.body,
    html = document.documentElement;

  var height = $("#map").height();
  var width = $("#map").width();

  var projection = d3.geo.equirectangular()
                    .scale(115)
                    .translate( [width/2, height / 2]);

  var path = d3.geo.path()
    .projection(projection);

  var svg = d3.select("#map").append("svg")
    .attr("width", width)
    .attr("height", height);

  d3.json("https://raw.githubusercontent.com/jdamiani27/Data-Visualization-and-D3/master/lesson4/world_countries.json", function(json){
    svg.selectAll("path")
      .data(json.features)
      .enter()
      .append("path")
        .attr("d",path)
        .attr("class", "countries")
  });

  var initialData;
  var barChartData;

  d3.csv("https://raw.githubusercontent.com/cov-lineages/cov-support/master/cov_support/data/country_coordinates.csv", function(coordsCsv) {
    d3.csv("https://raw.githubusercontent.com/cov-lineages/lineages-website/master/_data/lineages.metadata.csv",function(metadata) {
      metadata = metadata.filter(function(d) {
        if(d.lineage == selectedLineage || children.includes(d.lineage)) {
          return true;
        }
        return false;
      });

      var countryCentroidMap = new Map();

      coordsCsv.forEach(function(country) {
        countryCentroidMap[country.Country.toUpperCase()] = country;
      });

      var countryToCount = new Map();
      var dateToEntries = new Map();

      metadata.forEach(function(m) {
        m.country = m.country.toUpperCase();

        if(!countryToCount[m.country]) {
          countryToCount[m.country] = 0;
        }

        if(!dateToEntries[m.sample_date]) {
          dateToEntries[m.sample_date] = [];
        }

        dateToEntries[m.sample_date].push(m);

        countryToCount[m.country] = countryToCount[m.country] + 1;
      });

      initialData = [];
      barChartData = [];
      dateChartData = [];

      Object.keys(countryToCount).forEach(function(c) {  
        if(countryCentroidMap[c]) {
          var entry = {
            country: c,
            count: countryToCount[c],
            latitude: countryCentroidMap[c].Latitude,
            longitude: countryCentroidMap[c].Longitude,
            region: countryCentroidMap[c].Continent
          }

          initialData.push(entry);

          var barChartEntry = {
            country: c,
            count: countryToCount[c],
            region: countryCentroidMap[c].Continent
          }

          barChartData.push(barChartEntry);
        } else {
          console.log("unable to find centroid for: " + c);
        }

        barChartData = barChartData.sort((a,b) => (a.count > b.count) ? 1 : ((b.count > a.count) ? -1 : 0)); 

      });

      Object.keys(dateToEntries).forEach(function(d) {
        var regionToCounts = new Map();
        Object.keys(colourMap).forEach(function(k) {
          regionToCounts[k] = 0;
        });

        dateToEntries[d].forEach(function(e) {
          if(countryCentroidMap[e.country]) {
              regionToCounts[countryCentroidMap[e.country].Continent] = regionToCounts[countryCentroidMap[e.country].Continent] + 1;
          }
        });

        var entry = {};

        entry.date = d;

        var sum = 0;

        Object.keys(regionToCounts).forEach(function(r) {
          entry[r] = regionToCounts[r];

          sum = sum + regionToCounts[r];
        });

        if(sum > 0) {
           dateChartData.push(entry);
        }


      });

      drawLocations();
      drawBarChart(barChartData);
      drawDateChart(dateChartData);
    });
  });

  function drawLocations() {
    var div = d3.select("body").append("div") 
      .attr("class", "maptooltip");

    svg.selectAll("circle")
      .data(initialData)
      .enter()
      .append("circle")
      .attr("cx", function(d) {
      return projection([d.longitude, d.latitude])[0];
      })
      .attr("cy", function(d) {
      return projection([d.longitude, d.latitude])[1];
      })
      .attr("r", function(d) {
        // scale to number of cases, but capped at 40px to not completely cover map
        return Math.log(d.count) * 2;//Math.min(Math.max(d.count/ 20, 2), 50);
      })
      .attr("fill", function(d) {
        return colourMap[d.region];
      })
      .attr("class", "locations")
      .on("mouseover", function(d) { 
          $(".maptooltip").html(d.country + ": " + d.count + " sequences");
          $(".maptooltip").css({top: d3.event.pageY - 15, left: d3.event.pageX + 15, position:'absolute'});
          $(".maptooltip").show();
        })
        .on("mouseout", function(d) {   
            $(".maptooltip").hide();
        });
  };

  function drawBarChart(data) {
    var margin = {top: 20, right: 40, bottom: 160, left: 200},

    width = $("#bar_chart").width() - (margin.left + margin.right);
    height = $("#bar_chart").height() - (margin.top + margin.bottom);

    data = data.filter(function(d) {
        if(d.count >= 1) {
          return true;
        }

        return false;
      });

    data.sort(function(x, y){
       return d3.ascending(x.count, y.count);
    });

    var originalCountryCount = data.length;

    var maxBarSize = width;

    if(data.length <= 1) {
      maxBarSize = width / 3;
    }

    var x = d3.scale.ordinal().rangeRoundBands([0, maxBarSize], .05);

    var y = d3.scale.log().range([height, 0]);

    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom");

    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left")
        .ticks(10)
        .tickFormat(function (d) {
          return y.tickFormat(4,d3.format(",d"))(d)
        });

    var svg = d3.select("#bar_chart").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", 
              "translate(" + margin.left + "," + margin.top + ")");

      data = data.slice(Math.max(data.length - 25, 0))

      x.domain(data.map(function(d) { return d.country; }));
      y.domain([0.1, d3.max(data, function(d) { return d.count; })]);

      svg.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + height + ")")
          .call(xAxis)
        .selectAll("text")
          .style("text-anchor", "end")
          .attr("dx", "-.8em")
          .attr("dy", "-.55em")
          .attr("transform", "rotate(-90)" );

      svg.append("g")
          .attr("class", "y axis")
          .call(yAxis)
        .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", ".71em")
          .style("text-anchor", "end");

      svg.selectAll("bar")
          .data(data)
          .enter().append("rect")
          .attr("fill", function(d) {
            return colourMap[d.region];
          })
          .attr("x", function(d) { return x(d.country); })
          .attr("width", x.rangeBand())
          .attr("y", function(d) { return y(d.count); })
          .attr("height", function(d) { return height - y(d.count); })
          .on("mouseover", function(d) { 
            $(".maptooltip").html(d.country + ": " + d.count + " sequences");
            $(".maptooltip").css({top: d3.event.pageY - 15, left: d3.event.pageX + 15, position:'absolute'});
            $(".maptooltip").show();
          })
          .on("mouseout", function(d) {   
              $(".maptooltip").hide();
          });

      var lineLegend = svg.selectAll(".lineLegend").data(Object.keys(colourMap))
        .enter().append("g")
        .attr("class","lineLegend")
        .attr("transform", function (d,i) {
                return "translate(" + -200 + "," + (i*20) +")";
            });

      lineLegend.append("text").text(function (d) {return d;})
          .attr("transform", "translate(15,9)"); //align texts with boxes

      lineLegend.append("rect")
          .attr("fill", function (d, i) {return colourMap[d]; })
          .attr("width", 10).attr("height", 10);

      var messages = [data.length + "/" + originalCountryCount + " countries shown"];

      var countryCount = svg.selectAll(".countryCount").data(messages)
        .enter().append("g")
        .attr("class","lineLegend")
        .attr("transform", function (d,i) {
              return "translate(" + -200 + "," + (i*20) + 175 +")";
          });

      countryCount.append("text").text(function (d) {return d;}).attr("transform", "translate(0,9)");
  }

  function drawDateChart(data) {
    
    var margin = {top: 20, right: 0, bottom: 35, left: 30};

    var width = $("#date_chart").width();
    var height = $("#date_chart").height();

    var svg = d3.select("#date_chart")
      .append("svg")
      .attr("width", width -(margin.left + margin.right))
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var parse = d3.time.format("%Y-%m-%d").parse;


    // Transpose the data into layers
    var dataset = d3.layout.stack()(continents.map(function(region) {
      return data.map(function(d) {
        return {x: parse(d.date), y: +d[region], region: region};
      });
    }));


    var minDate, maxDate;

    data.forEach(function(d) {
      var date = parse(d.date);

      if(!minDate) {
        minDate = date;
        maxDate = date;
      }

      if(minDate > date) {
        minDate = date;
      }

      if(maxDate < date) {
        maxDate = date;
      }
    });

    var dates = [];

    while (minDate <= maxDate){
      dates.push(new Date(minDate));
      minDate.setDate(minDate.getDate() + 1);
    };

    var maxBandSize = 100 + (width - (margin.left + margin.right));

    if(minDate == maxDate) {
      maxBandSize = maxBandSize / 2;
    }

    // Set x, y and colors
    var x = d3.scale.ordinal()
      .domain(dates.map(function(d) { return d; }))
      .rangeRoundBands([0, maxBandSize], 0.01);

    var y = d3.scale.linear()
      .domain([0, d3.max(dataset, function(d) {  return d3.max(d, function(d) { return d.y0 + d.y; });  })])
      .range([height, 0]);

    var colors = [];
    for(var c of continents) {
      colors.push(colourMap[c]);
    }

    // Define and draw axes
    var yAxis = d3.svg.axis()
      .scale(y)
      .orient("left")
      .ticks(4)
      .tickSize(-width, 0, 0)
      .tickFormat( function(d) { return d } );
    
    var ticks = x.domain().filter(function(d,i){ return d.getDate() == 15; } );

    var xAxis = d3.svg.axis()
      .scale(x)
      .orient("bottom")
      .tickFormat(d3.time.format("%b"))
      .tickValues(ticks);

    svg.append("g")
      .attr("class", "y axis")
      .call(yAxis);

    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "rotate(-90)" )
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

    var formatDate = d3.time.format("%d-%b-%Y")

    // Create groups for each series, rects for each segment 
    var groups = svg.selectAll("g.sequences")
      .data(dataset)
      .enter().append("g")
      .attr("class", "sequences")
      .style("fill", function(d, i) { return colors[i]; });

    var rect = groups.selectAll("rect")
      .data(function(d) { return d; })
      .enter()
      .append("rect")
      .attr("x", function(d) { return x(d.x); })
      .attr("y", function(d) { return y(d.y0 + d.y); })
      .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); })
      .attr("width", x.rangeBand())
      .on("mouseover", function(d, i) { 
        $(".maptooltip").html(formatDate(d.x) + "<br>" + d.y + " sequences<br>" + d.region);
        $(".maptooltip").css({top: d3.event.pageY - 15, left: d3.event.pageX + 15});
        $(".maptooltip").show();
      })
      .on("mouseout", function(d) {   
          $(".maptooltip").hide();
      });
  }

</script>